﻿/**

3000！ 约2秒 
*/
using ConsoleAlgorithms;
using System;
using System.Collections.Generic;
using System.Text;

namespace HelloWorld.Utils
{
    public class BigInteger : ITestable
    {

        public void Test()
        {
            //BigInteger b1 = new BigInteger(12345);
            //BigInteger b2 = new BigInteger(3);
            //BigInteger b3 = b1 + b2;

            //Console.WriteLine($"b1: {b1.ToString()}, bts.Count: {b1.Length}");
            //Console.WriteLine($"b2: {b2.ToString()}, bts.Count: {b2.Length}");
            //Console.WriteLine($"b3: {b3.ToString()}, bts.Count: {b3.Length}");

            //BigInteger b4 = b1 * b1;
            //Console.WriteLine($"b4: {b4}");

            //var v1 = new BigInteger(362880);
            //var v2 = new BigInteger(10);
            //Console.WriteLine($"{v1} * {v2} = {v1 * v2}");

            
            for (int i = 0; i < 10; i++)
            {
                OneTest();
            }
        }

        public static void OneTest()
        {
            DateTime t1 = DateTime.Now;
            BigInteger b5 = new BigInteger(1);
            for (int i = 1; i <= 3000; i++)
            {
                // var s = b5.ToString();
                BigInteger bi = new BigInteger(i);
                b5 = b5 * bi;
                // Console.WriteLine($"b5 * bi: {s} * {bi} = {b5}");
            }
            DateTime t2 = DateTime.Now;


            var time = (t2 - t1).TotalMilliseconds;
            Console.WriteLine($"BigInteger: Time: {time:0.0}ms, b.length:{b5.ToString().Length}");
        }

        public List<byte> Bytes = new List<byte>();
        public int Sign = 1;


        public BigInteger() { }

        public BigInteger(long v)
        {
            long v0 = v;
            Bytes.Clear();
            while (v0 > 0)
            {
                Bytes.Add((byte)(v0 % 10));
                v0 = v0 / 10;
            }

            // 123 -> {3,2,1}, bts[0] = 3, bts[1] = 2, bts[2] = 3
        }


        /// <summary>
        /// 读取或设置指定的索引的值。
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public byte this[int index]
        {
            get { return Bytes[index]; }
            set { Bytes[index] = value; }
        }



        public static BigInteger operator +(BigInteger b1, BigInteger b2)
        {
            BigInteger b3 = b1.Clone();

            while (b3.Length < b2.Length)
                b3.Bytes.Add(0);

            for (int i = 0; i < b2.Length; i++)
                b3[i] += b2[i];

            b3.normalize();

            return b3;
        }

        public static BigInteger operator *(BigInteger b1, BigInteger b2)
        {
            BigInteger b3 = new BigInteger();
            b3.Bytes = new List<byte>();
            for (int i = 0; i < b1.Length + b2.Length + 1; i++)
                b3.Bytes.Add(0);

            for (int i = 0; i < b2.Length; i++)
            {
                for (int j = 0; j < b1.Length; j++)
                {
                    b3[j + i] += (byte)(b1[j] * b2[i]);
                }
                b3.normalize(false);
            }
            b3.normalize();
            return b3;
        }

        public int Compare(BigInteger b1, BigInteger b2)
        {
            int res = 0;
            if (b1.Length == b2.Length)
            {
                for (int i = b1.Length - 1; i >= 0; i--)
                {
                    if (b1[i] != b2[i])
                    {
                        res = b1[i] > b2[i] ? 1 : -1;
                        break;
                    }

                }
            }
            else
            {
                res = b1.Length > b2.Length ? 1 : -1;
            }

            return res;
        }


        public static BigInteger operator /(BigInteger b1, BigInteger b2)
        {

            return null;
        }

        public static bool operator ==(BigInteger b1, BigInteger b2)
        {

            return true;
        }

        public static bool operator !=(BigInteger b1, BigInteger b2)
        {

            return true;
        }

        public static bool operator >(BigInteger b1, BigInteger b2)
        {

            return true;
        }

        public static bool operator <(BigInteger b1, BigInteger b2)
        {

            return true;
        }

        public static bool operator >=(BigInteger b1, BigInteger b2)
        {

            return true;
        }

        public static bool operator <=(BigInteger b1, BigInteger b2)
        {

            return true;
        }

        public BigInteger Clone()
        {
            var b = new BigInteger();
            b.Bytes = new List<byte>();
            for (int i = 0; i < Bytes.Count; i++)
                b.Bytes.Add(Bytes[i]);
            return b;
        }

        /// <summary>
        /// 数据长度。
        /// </summary>
        public int Length { get => Bytes.Count; }


        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < Length; i++)
            {
                // if (i > 0 && i % 3 == 0) sb.Insert(0, ',');
                sb.Insert(0, this[i]);
            }
            if (Sign < 0)
                sb.Insert(0, '-');

            return sb.ToString();
        }

        void normalize(bool removeZeros = true)
        {
            Bytes.Add(0);
            for (int i = 0; i < Bytes.Count - 1; i++)
            {
                if (Bytes[i] >= 10)
                {
                    Bytes[i + 1] += (byte)(Bytes[i] / 10);
                    Bytes[i] = (byte)(Bytes[i] % 10);
                }
            }

            while (removeZeros && Bytes.Count > 0 && Bytes[Bytes.Count - 1] == 0)
                Bytes.RemoveAt(Bytes.Count - 1);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(this, obj))
            {
                return true;
            }

            if (ReferenceEquals(obj, null))
            {
                return false;
            }

            throw new NotImplementedException();
        }

        public override int GetHashCode()
        {
            throw new NotImplementedException();
        }
    }
}
